package com.example.net.http

import android.text.TextUtils
import android.util.Log
import com.example.baseutils.*
import com.example.baseutils.Constance.FANTACY_BASE_URL
import com.example.baseutils.Constance.CHAT_NEW_V2_BASE_URL
import com.example.baseutils.Constance.CHAT_SCORE_BASE_URL
import com.example.baseutils.application.BaseApplication
import com.example.net.http.request.*
import com.example.net.http.response.*
import com.example.net.utils.HttpUtils
import com.example.net.utils.SecurityUtils
import com.google.gson.Gson
import okhttp3.*
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.ResponseBody.Companion.toResponseBody
import okhttp3.logging.HttpLoggingInterceptor
import okio.Buffer
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import java.io.File
import java.nio.charset.Charset
import java.util.concurrent.TimeUnit


/**
 * Author by lp,on 2024年02月14日13:54:57
 * 新版本Chat请求信息
 */
object FantacyRetrofitCreator {
    private val TAG = "ChatNewRetrofitCreator"


    var userName = MySharedPreferences.read(Constance.AI_USER_NAME, "") ?: ""
    var robotId = MySharedPreferences.read(Constance.ROBOT_ID, "1") ?: "1"
    var accessToken = MySharedPreferences.read(Constance.Authorization, "") ?: ""
    var refreshToken = MySharedPreferences.read(Constance.REFRESH_TOKEN, "") ?: ""
    var expireTime = MySharedPreferences.read(Constance.EXPIRESTIME, -1L) ?: -1L
    var refreshExpireTime = MySharedPreferences.read(Constance.REFRESH_EXPIRESTIME, -1L) ?: -1L

    private val deviceNo: String by lazy { AppUtils.getLocalMacAddressFromWifiInfo() }
    private var tokenTime = 0L
    private var refreshTime = 0L

    //拦截者
    private val headerInterceptor = Interceptor { chain ->
        val request = chain.request().newBuilder().addHeader("deviceNo", deviceNo)
            .addHeader("device_no", deviceNo).build()
        Log.i("RetrofitCreator", "request body $deviceNo: $request")
        val response = chain.proceed(request)
        response
    }


    val httpLoggingInterceptor = HttpLoggingInterceptor().apply {

        level = HttpLoggingInterceptor.Level.BODY
    }

    private val chatClient = OkHttpClient.Builder().addInterceptor(cacheInterceptor())
        .addInterceptor(httpLoggingInterceptor)
        .connectTimeout(10, TimeUnit.SECONDS)
        .readTimeout(10, TimeUnit.SECONDS)
//        .retryOnConnectionFailure(true)
        .writeTimeout(10, TimeUnit.SECONDS)
        .build()
    private val fantacyClient = OkHttpClient.Builder().addInterceptor(cacheInterceptor())
        .addInterceptor(httpLoggingInterceptor)
        .connectTimeout(100, TimeUnit.SECONDS)
        .readTimeout(100, TimeUnit.SECONDS)
//        .retryOnConnectionFailure(true)
        .writeTimeout(100, TimeUnit.SECONDS)
        .build()

    private val chatRetrofit = Retrofit.Builder()
        .baseUrl(CHAT_NEW_V2_BASE_URL)
        .client(chatClient)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
    private val scoreRetrofit = Retrofit.Builder()
        .baseUrl(CHAT_SCORE_BASE_URL)
        .client(chatClient)
        .addConverterFactory(GsonConverterFactory.create())
        .build()
    private val fantacyRetrofit = Retrofit.Builder()
        .baseUrl(FANTACY_BASE_URL)
        .client(fantacyClient)
        .addConverterFactory(GsonConverterFactory.create())
        .build()


    val chatService: ChatNewService = chatRetrofit.create(ChatNewService::class.java)
    val scoreService: ChatNewService = scoreRetrofit.create(ChatNewService::class.java)
    val fantacyService: FantacyService = fantacyRetrofit.create(FantacyService::class.java)

    /**
     * 缓存数据拦截器
     *
     * @param mContext Context
     * @param key      秘钥
     */
    private class cacheInterceptor() : Interceptor {
        override fun intercept(chain: Interceptor.Chain): okhttp3.Response {
            val request = chain.request().newBuilder()
//                .addHeader("Authorization", "Basic dXNlcjE4Om15cGFzczEyMw==")
//                .addHeader("api-version", "v2")
//                .addHeader("content-type", "application/json")
                .build()


            val requestBody = request.body
            var body = "null"
            if (requestBody != null) {
                val buffer = Buffer()
                requestBody.writeTo(buffer)
                var charset: Charset = java.nio.charset.StandardCharsets.UTF_8
                body = buffer.readString(charset)
            }
            request.url
            val requestJson = body
            Log.i(TAG, "cacheInterceptor: requestJson $requestJson")
            if (!request.url.toString().contains("login")) {
                val response = chain.proceed(request)
//                Log.i(TAG, "非cacheTime: ")
                return response
            }
            Log.e(TAG, "缓存的接口")
            Log.i(TAG, "expiresTime:$expireTime ")
            // 缓存时间
            val cacheKey = HttpUtils.getCacheKey(request)
            var key = cacheKey
            val cacheFile = File(HttpUtils.getCacheFile(BaseApplication.instance), cacheKey)
            val cacheEnable = (System.currentTimeMillis() - cacheFile.lastModified()) < expireTime
            Log.i(TAG, "cacheEnable: $cacheEnable")
            if (cacheEnable && cacheFile.exists() && cacheFile.length() > 0) {
                Log.e(
                    TAG,
                    "[intercept] 缓存模式 url:${HttpUtils.getRequestUrl(request)} " + "过期时间:${
                        HttpUtils.dateTimeToString(expireTime)
                    }"
                )
                val cache = SecurityUtils.decryptContent(cacheFile.readText(), key)
                if (cache.isNotEmpty() && cache.startsWith("{") && cache.endsWith("}")) {
                    Log.i(TAG, "from disk cache: $cache")
                    return okhttp3.Response.Builder()
                        .code(200)
                        .body(cache.toResponseBody())
                        .request(request)
                        .message("from disk cache")
                        .protocol(Protocol.HTTP_2)
                        .build()
                }
            }
            val response = chain.proceed(request)
            //response.body?.string()只能读取一次 就流会被close
            val dataString = response.body?.string() ?: return response
            // 写入缓存
            if (response.code == 200) {
                Log.i(TAG, "-------save cache--------")
                // Json数据写入缓存
                cacheFile.writeText(SecurityUtils.encryptContent(dataString, key))
            } else {
                Log.i(TAG, "-------response error--------" + response.message)
                cacheFile.writeText("")
            }
            return response.newBuilder()
                .message(response.message)
                .body(dataString.toResponseBody(response.body?.contentType()))
                .build()
        }
    }


    private fun saveToken(token: String) {
        if (accessToken == token || token.isNullOrEmpty()) {
            Log.e(TAG, "saveToken: 无需更新 $accessToken")
            return
        }
        tokenTime = System.currentTimeMillis()
        accessToken = token
        Log.e(TAG, "saveToken 更新accessToken $accessToken  expireTime$tokenTime")
        MySharedPreferences.save {
            putString(Constance.Authorization, accessToken)
        }
    }

    suspend fun getDeviceInfo(deviceNo: String = this.deviceNo): DeviceResponse? {
        Log.i(TAG, "getDeviceInfo before $deviceNo")
        try {
            val result = fantacyService.getDeviceInfo(deviceNo)
            if(result?.data != null){
                MySharedPreferences.save {
                    putString(Constance.SERVICE_CALL, result.data?.serviceCall?:"000")
                }
            }
            "getDeviceInfo result $result  ${result}".log(TAG)
            return result.data
        } catch (e: Exception) {
            e.printStackTrace()
            Log.e(TAG, "${e.message}")
        }
        return null
    }

    suspend fun getBanner(sceneId: Int): BannerResponse? {
        Log.i(TAG, "getBanner before $deviceNo")
        try {
            val result = fantacyService.getBanner(sceneId)
            "getBanner result $result  ${result}".log(TAG)
            return result.data
        } catch (e: Exception) {
            e.printStackTrace()
            Log.e(TAG, "${e.message}")
        }
        return null
    }

    suspend fun pushPhoto(spuId: Int,uploadPic:String): MergeResponse? {
        Log.i(TAG, "pushPhoto before $spuId")
        try {
            val requestJson= "{\"spuId\":\"$spuId\",\"uploadPic\":\"$uploadPic\"}"
            val requestBody =
                RequestBody.create(
                    "application/json;charset=utf-8".toMediaTypeOrNull(),requestJson )
            val result = fantacyService.pushPhoto(requestBody)
            "pushPhoto result $result  ${result}".log(TAG)
            return result.data
        } catch (e: Exception) {
            e.printStackTrace()
            Log.e(TAG, "${e.message}")
        }
        return null
    }

    suspend fun pushHeart(): Boolean? {
        Log.i(TAG, "pushHeart before $deviceNo")
        try {
            val requestJson= "{\"no\":\"$deviceNo\"}"
            val requestBody =
                RequestBody.create(
                    "application/json;charset=utf-8".toMediaTypeOrNull(),requestJson )
            val result = fantacyService.pushHeart(requestBody)
            "pushHeart result $result  ${result}".log(TAG)
            return true
        } catch (e: Exception) {
            e.printStackTrace()
            Log.e(TAG, "${e.message}")
        }
        return false
    }
    suspend fun queryQr(sceneId: Int): QrResponse? {
        Log.i(TAG, "queryQr before $sceneId")
        try {
            val result = fantacyService.queryQr(sceneId)
            "queryQr result $result  ${result}".log(TAG)
            return result.data
        } catch (e: Exception) {
            e.printStackTrace()
            Log.e(TAG, "${e.message}")
        }
        return null
    }
    suspend fun checkPay(orderId: Int): Boolean {
        Log.i(TAG, "checkPay before $orderId")
        try {
            val result = fantacyService.checkPay(orderId)
            "checkPay result $result  ${result}".log(TAG)
            return result.data?:false
        } catch (e: Exception) {
            e.printStackTrace()
            Log.e(TAG, "${e.message}")
        }
        return false
    }
    /**
     * name:sichuan
     * password:admin
     * 登录
     * */
    suspend fun login(userName: String, password: String): Boolean {
        Log.i(TAG, "login before ")
        try {
            val requestBody =
                RequestBody.create(
                    "application/json;charset=utf-8".toMediaTypeOrNull(),
                    "{\n" +
                            "\"username\": \"$userName\",\n" +
                            "\"password\": \"$password\"\n" +
                            "}"
                )
            val result = chatService.loginChat(requestBody)
            saveToken(result.data.accessToken)
            "login result $result".log(TAG)
            return true
        } catch (e: Exception) {
            e.printStackTrace()
            Log.e(TAG, "${e.message}")
        }
        return false
    }

    fun isNeedRefresh(): Boolean {
        if (System.currentTimeMillis() - tokenTime < 60 * 60 * 1000 * 2)
            return false
        return true
    }

    suspend fun refreshToken(): Boolean {
        Log.i(TAG, "refreshToken before ")
        if (!isNeedRefresh())
            return false
        try {
            chatService.refreshToken(accessToken, refreshToken)?.let {
                refreshTime = System.currentTimeMillis()
//                saveToken(
//                    it.access_token,
//                    it.access_expiry,
//                    it.refresh_token,
//                    it.refresh_expiry
//                )
                "refreshToken result $it".log(TAG)
                return true
            }
            return false
        } catch (e: Exception) {
            e.printStackTrace()
            Log.e(TAG, "${e.message}")
        }
        return false
    }

    /**
     *
     * 注册
     * */
    suspend fun createUser(type: String, refresh: Boolean = true): String? {
        Log.i(TAG, "createUser before ")
        if (TextUtils.isEmpty(userName) || !userName.contains(type) || refresh) {
            Log.e(TAG, "createUser: refresh")
            userName = "$type" + TimeUtil.getYMDHMS_SSSDate()
        }
        val request = AddUserRequest(userName)
        try {
            val requestJson = Gson().toJson(request)
            Log.i(TAG, "createUser  requestJson $requestJson")
            val requestBody =
                RequestBody.create(
                    "application/json;charset=utf-8".toMediaTypeOrNull(),
                    requestJson
                )
            val result = chatService.createUser(requestBody, accessToken)
            if (result != null) {
                if (result.statusCode == 200) {
                    MySharedPreferences.save {
                        putString(Constance.AI_USER_NAME, userName)
                    }
                    return userName
                }
                if (result.message.contains("exist")) {
                    return userName
                }
            }
            "createUser result $result".log(TAG)
        } catch (e: Exception) {
            e.printStackTrace()
            Log.e(TAG, "${e.message}")
        }
        return null
    }

    /**
     *
     * 保存机器人
     * */
    suspend fun saveUserRobot(): Boolean {
        Log.i(TAG, "saveUserRobot before ")
        val request = AddRobotRequest()
        try {
            val requestJson = Gson().toJson(request)
            val requestBody =
                RequestBody.create(
                    "application/json;charset=utf-8".toMediaTypeOrNull(),
                    requestJson
                )
            val result = chatService.saveUserRobot(requestBody, accessToken)
            "saveUserRobot result $result".log(TAG)
            if (result.status == 0) {
                robotId = result.data?.robotId ?: "1"
                MySharedPreferences.save { putString(Constance.ROBOT_ID, robotId) }
                return true
            }
        } catch (e: Exception) {
            e.printStackTrace()
            Log.e(TAG, "${e.message}")
        }
        return false
    }

    /**
     *
     * 获取结果
     * */
    suspend fun getScore(startTime: Long, endTime: Long): ScoreResponse? {
        Log.i(TAG, "getScore before ")
        val request = ChatScoreRequest(robotId.toInt(), startTime, endTime)
        try {
            val requestJson = Gson().toJson(request)
            Log.i(TAG, "getScore  requestJson $requestJson")
            val requestBody =
                RequestBody.create(
                    "application/json;charset=utf-8".toMediaTypeOrNull(),
                    requestJson
                )
            val result = chatService.getScore(requestBody, accessToken)
            "getScore result $result".log(TAG)
            return result.data
        } catch (e: Exception) {
            e.printStackTrace()
            Log.e(TAG, "${e.message}")
        }
        return null
    }

    interface AsrCallBack {
        fun getResult(result: String?)
        fun error()
    }

    /**
     *
     * 获取结果
     * */
    fun getAsr(file: File, asrCallBack: AsrCallBack) {
        Log.i(TAG, "getAsr before ")
        try {
            val requestBody =
                RequestBody.create("application/octet-stream".toMediaTypeOrNull(), file)
            val call = chatService.getAsr(requestBody, accessToken)
            call.enqueue(object : Callback<BaseResponse<String>> {
                override fun onResponse(
                    call: Call<BaseResponse<String>>,
                    response: Response<BaseResponse<String>>
                ) {
                    if (response.body()?.statusCode == 200)
                        asrCallBack.getResult(response.body()?.data)
                    else
                        asrCallBack.error()
                }

                override fun onFailure(call: Call<BaseResponse<String>>, t: Throwable) {
                    asrCallBack.error()
                }

            })
        } catch (e: Exception) {
            e.printStackTrace()
            Log.e(TAG, "${e.message}")
        }
    }
}

